package nosql.query;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import nosql.MysqlConnector;
import nosql.NosqlException;
import nosql.property.Property;
import nosql.property.PropertySet;
import nosql.property.PropertySetBuilder;

import org.json.simple.parser.ParseException;


/**
 * Nosql operation include: insert, query
 * @author Yexi Jiang <http://sites.google.com/site/yexijiang/>
 *
 */
public class NosqlStatement {
	private MysqlConnector mysqlConnector;

	public NosqlStatement(MysqlConnector connector){
		this.mysqlConnector = connector;
	}
	
	/**
	 * Insert an entity.
	 * @param entity
	 * @throws ParseException
	 * @throws SQLException 
	 * @throws NosqlException 
	 */
	public void insert(String entity) throws ParseException, NosqlException, SQLException{
		//	get property set by parsing entity
		PropertySetBuilder builder = new PropertySetBuilder();
		PropertySet propertySet = builder.store(entity);
		
		//	insert new properties
		Set<String> propertyNames = propertySet.getPropertyNameSet();
		
		//	insert entityId record into table $
		String uuid = UUID.randomUUID().toString();
		StringBuilder stringBuilder = new StringBuilder();
		mysqlConnector.addProperties(propertyNames, stringBuilder);
		String propertiesString = stringBuilder.toString();	//	store the properties related to entityId

		String insertEntityRecordSql = "insert into $(entityId, properties) values('" + uuid +"','"
					+ propertiesString + "');";
		
		//	insert entity into database
		Statement stmt = null;
		stmt = mysqlConnector.getConnection().createStatement();
		try {

			stmt.execute(insertEntityRecordSql);
			int ii = 0;
			for(Property property : propertySet){
				++ii;
				//	update adjacency list
//				ResultSet adjResultSet = stmt.executeQuery("select relatedProperty from _ where property='" + property.getTableName() + "'");
//				adjResultSet.last();
//				int rowCount = adjResultSet.getRow();
//				
//				String relatedPropertiesString = "";	//	related properties to current property
//				for(Property prop : propertySet){
//					relatedPropertiesString += prop.getTableName() + ":1,";
//				}
//				if(rowCount == 0){
//					relatedPropertiesString = relatedPropertiesString.substring(0, relatedPropertiesString.length() - 1);
//					stmt.execute("insert into _(property, relatedProperty) values('" + property.getTableName() + "','" + relatedPropertiesString + "');");
//				}else{
//					adjResultSet.beforeFirst();
//					adjResultSet.next();
//					String text = adjResultSet.getString("relatedProperty");
//					String[] relatedProperties = text.split(",");
//					List<String> propertyList = new ArrayList<String>();
//					List<Integer> propertyRelatedStrengthList = new ArrayList<Integer>();
//					for(String relatedProperty : relatedProperties){
//						String[] record = relatedProperty.split(":");
//						propertyList.add(record[0]);
//						propertyRelatedStrengthList.add(Integer.parseInt(record[1]));
//					}
//					//	update
//					for(Property prop : propertySet){
//						boolean propExists = false;
//						for(int idx = 0; idx < propertyList.size(); ++idx){
//							if(prop.getTableName().equals(propertyList.get(idx))){
//								Integer value = propertyRelatedStrengthList.get(idx) + 1;
//								propertyRelatedStrengthList.set(idx, value);
//								propExists = true;
//								break;
//							}
//						}
//						if(propExists = false){
//							propertyList.add(prop.getTableName());
//							propertyRelatedStrengthList.add(1);
//						}
//					}
//					//	construct new string
//					String newText = "";
//					for(int idx = 0; idx < propertyList.size(); ++idx){
//						newText += propertyList.get(idx) + ":" + propertyRelatedStrengthList.get(idx) + ",";
//					}
//					newText = newText.substring(0, newText.length() - 1);
//					
//					stmt.execute("update _ set relatedProperty='" + newText + "' where property='" + property.getTableName() + "'");
//				}
//				adjResultSet.close();
//				
//				//	update related properties
//				for(Property prop : propertySet){
//					if(prop.getTableName().equals(property.getTableName()))
//						continue;
//					ResultSet relatedResultSet = stmt.executeQuery("select relatedProperty from _ where property='" + prop.getTableName() + "';");
//					relatedResultSet.last();
//					int count = relatedResultSet.getRow();
//					if(count == 0){	//	current related property record not exists yet
//						stmt.execute("insert into _(property, relatedProperty) values('" + prop.getTableName() + "','" + property.getTableName() + ":1');");
//					}
//					else{
//						relatedResultSet.beforeFirst();
//						relatedResultSet.next();
//						String text = relatedResultSet.getString("relatedProperty");
//						String[] relatedProperties = text.split(",");
//						int propertyOccuranceIndex = text.indexOf(property.getTableName());
//						if(propertyOccuranceIndex < 0){	//	no property exists in list
//							stmt.execute("update  _ set relatedProperty='" +  text + "," + property.getTableName() + ":1" + "' where property='" + prop.getTableName() + "';");
//						}
//						else{
//							String[] properties = text.split(",");
//							for(String p : properties){
//								String[] record = p.split(":");
//								if(property.equals(record[0])){
//									Integer relatedStrength = Integer.parseInt(record[1]) + 1;
//									stmt.execute("update  _ set relatedProperty='" + text.replace(p, record[0] + ":" + relatedStrength.toString()) + "' where property='" + prop.getTableName() + "';");
//									break;
//								}
//							}
//						}
//					}
//					relatedResultSet.close();
//				}

				String insertString = "insert into `" + property.getTableName() 
					+ "`(entityId, ref) values('" + uuid +"', '" 
					+ property.getRef() +"');";
				stmt.execute(insertString);
//				System.out.println(insertString);
			}
			mysqlConnector.getConnection().commit();
		} catch (SQLException e) {
			mysqlConnector.getConnection().rollback();
			e.printStackTrace();
		}
	}
	
	/**
	 * Create query instance.
	 * @return
	 */
	public NosqlQuery createQuery(){
		return new NosqlQuery(mysqlConnector);
	}
	
}
